package main

import (
	"fmt"
	"github.com/urfave/cli"
	"io"
	"log"
	"os"
	"strings"
	"text/tabwriter"
)

var err error

// CreateCommands Creates all CLI commands
func createCommands() []cli.Command {
	return []cli.Command{
		createRun(),
		createDNS(),
		createDeploy(),
	}
}

func createRun() cli.Command {
	return cli.Command{
		Name:  "run",
		Usage: "Register an account, then create and install a certificate",
		Before: func(ctx *cli.Context) error {
			// we require either domains or csr, but not both
			hasDomains := len(ctx.GlobalStringSlice("domains")) > 0
			hasCsr := len(ctx.GlobalString("csr")) > 0
			if hasDomains && hasCsr {
				log.Fatal("Please specify either --domains/-d or --csr/-c, but not both")
			}
			if !hasDomains && !hasCsr {
				log.Fatal("Please specify --domains/-d (or --csr/-c if you already have a CSR)")
			}
			return nil
		},
		Action: run,
		Flags: []cli.Flag{
			cli.BoolFlag{
				Name:  "no-bundle",
				Usage: "Do not create a certificate bundle by adding the issuers certificate to the new certificate.",
			},
			cli.BoolFlag{
				Name:  "must-staple",
				Usage: "Include the OCSP must staple TLS extension in the CSR and generated certificate. Only works if the CSR is generated by acme.",
			},
		},
	}
}

func createDNS() cli.Command {
	return cli.Command{
		Name:   "dns",
		Usage:  "Shows additional help for the '--dns' global option",
		Action: dnsHelp,
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "code, c",
				Usage: fmt.Sprintf("DNS code: %s", allDNSCodes()),
			},
		},
	}
}

func dnsHelp(ctx *cli.Context) error {
	code := ctx.String("code")
	if code == "" {
		w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
		ew := &errWriter{w: w}
		ew.writeln(`Credentials for DNS providers must be passed through environment variables.`)
		ew.writeln()
		ew.writeln(`To display the documentation for a DNS providers:`)
		ew.writeln()
		ew.writeln("\t$ acme dns -c code")
		ew.writeln()
		ew.writeln("All DNS codes:")
		ew.writef("\t%s\n", allDNSCodes())
		ew.writeln()
		ew.writeln("More information: https://go-acme.github.io/lego/dns")

		if ew.err != nil {
			return ew.err
		}

		return w.Flush()
	}
	return displayDNSHelp(strings.ToLower(code))
}

func createDeploy() cli.Command {
	return cli.Command{
		Name:   "deploy",
		Usage:  "Shows additional help for the '--deploy' global option",
		Action: deployHelp,
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "code, c",
				Usage: fmt.Sprintf("Deploy code: %s", allDNSCodes()),
			},
		},
	}
}

func deployHelp(ctx *cli.Context) error {
	code := ctx.String("code")
	if code == "" {
		w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
		ew := &errWriter{w: w}
		ew.writeln(`Credentials for Deploy providers must be passed through environment variables.`)
		ew.writeln()
		ew.writeln(`To display the documentation for a Deploy providers:`)
		ew.writeln()
		ew.writeln("\t$ acme deploy -c code")
		ew.writeln()
		ew.writeln("All Deploy codes:")
		ew.writef("\t%s\n", allDeployCodes())

		if ew.err != nil {
			return ew.err
		}

		return w.Flush()
	}
	return displayDeployHelp(strings.ToLower(code))
}

type errWriter struct {
	w   io.Writer
	err error
}

func (ew *errWriter) writeln(a ...interface{}) {
	if ew.err != nil {
		return
	}

	_, ew.err = fmt.Fprintln(ew.w, a...)
}

func (ew *errWriter) writef(format string, a ...interface{}) {
	if ew.err != nil {
		return
	}

	_, ew.err = fmt.Fprintf(ew.w, format, a...)
}
